package com.factory.comport.uart;

import com.factory.comport.helper.ModbusCRC;
import com.factory.comport.helper.constants.ModbusConstants;
import java.util.Timer;
import java.util.TimerTask;
import java.util.logging.Level;
import java.util.logging.Logger;
import jssc.SerialPort;
import jssc.SerialPortException;

public class UARTSendTimer {
    //TODO: fix this program to fit the requirement
    //Currently, just request 120 byte of Data

    private long m_timeInterval;
    private SerialPort m_pSerialPort;
    private int m_ComStatus = 0;
    private byte m_memormyAddressL;
    private byte m_memorymAddressH;
    private byte m_modBusFunctionCode;
    private byte m_comLengthL;
    private byte m_comLengthH;
    private Timer m_pTimer;

    public UARTSendTimer(SerialPort serialPort, long timeInterval) {
        this.m_pSerialPort = serialPort;
        m_timeInterval = timeInterval;
        m_pTimer = new Timer();
    }

    public void start() {
        m_pTimer.schedule(new RequestDataTask(), m_timeInterval, m_timeInterval);
    }

    public void stop() {
        m_pTimer.cancel();
    }

    private class RequestDataTask extends TimerTask {

        private byte[] m_pSendBytes = new byte[ModbusConstants.MOBUS_REQUEST_MESSAGE_LENGTH];

        @Override
        public void run() {
            if (m_pSerialPort.isOpened()) {
                try {
                    switch (m_ComStatus) {
                        case 0: //Ask for segment 1
                            configureModbus(ModbusConstants.DATA_ADDRESS_FOR_SEGMENT_1,
                                    ModbusConstants.MODBUS_REQUEST_LENGTH_OF_DATA);
                            m_pSerialPort.readBytes();  //Clear the buffer
                            m_pSerialPort.writeBytes(m_pSendBytes);
                            System.out.println("Minh Luan: sent data for segment 1");
                            break;

                        case 1: //Ask for segment 2
                            configureModbus(ModbusConstants.DATA_ADDRESS_FOR_SEGMENT_2,
                                    ModbusConstants.MODBUS_REQUEST_LENGTH_OF_DATA);
                            m_pSerialPort.readBytes();  //Clear the buffer
                            m_pSerialPort.writeBytes(m_pSendBytes);
                            System.out.println("Minh Luan: sent data for segment 2");
                            break;

//                        case 2: //Ask for segment 3
//                            configureModbus(0x18, 0x0C);
//                            m_pSerialPort.writeBytes(m_pSendBytes);
//                            break;
//
//                        case 3: //Ask for segment 4
//                            configureModbus(0x24, 0x0C);
//                            m_pSerialPort.writeBytes(m_pSendBytes);
//                            break;
//
//                        case 4: //Ask for segment 5
//                            configureModbus(0x30, 0x0C);
//                            m_pSerialPort.writeBytes(m_pSendBytes);
//                            break;
//
//                        case 5: //Ask for segment 6
//                            configureModbus(0x3C, 0x0C);
//                            m_pSerialPort.writeBytes(m_pSendBytes);
//                            break;
//
//                        case 6: //Ask for segment 7
//                            configureModbus(0x48, 0x0C);
//                            m_pSerialPort.writeBytes(m_pSendBytes);
//                            break;
//
//                        case 7: //Ask for segment 8
//                            configureModbus(0x54, 0x0C);
//                            m_pSerialPort.writeBytes(m_pSendBytes);
//                            break;
//
//                        case 8: //Ask for segment 9
//                            configureModbus(0x60, 0x0C);
//                            m_pSerialPort.writeBytes(m_pSendBytes);
//                            break;
//
//                        case 9: //Ask for segment 10
//                            configureModbus(0x6C, 0x0C);
//                            m_pSerialPort.writeBytes(m_pSendBytes);
//                            break;

                        default:
                            break;
                    }
                    m_ComStatus++;
                    if (m_ComStatus >= 2) {
                        m_ComStatus = 0;
                    }
                } catch (SerialPortException ex) {
                    Logger.getLogger(UARTSendTimer.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }

        private void configureModbus(int memoryAddress, int comLength) {
            // Modbus function code to request for data
            m_modBusFunctionCode = ModbusConstants.MODBUS_REQUEST_FUNCTION_CODE;

            //The data length to request
            m_comLengthH = (byte) ((comLength & 0x0000ff00) >> 8);
            m_comLengthL = (byte) (comLength & 0x000000ff);

            //The data address to request
            m_memorymAddressH = (byte) ((memoryAddress & 0x0000ff00) >> 0x08);
            m_memormyAddressL = (byte) (memoryAddress & 0x000000ff);

            m_pSendBytes[0] = ModbusConstants.DEVICE_ADDRESS;
            m_pSendBytes[1] = m_modBusFunctionCode;
            m_pSendBytes[2] = m_memorymAddressH;
            m_pSendBytes[3] = m_memormyAddressL;
            m_pSendBytes[4] = m_comLengthH;
            m_pSendBytes[5] = m_comLengthL;

            //The CRC in the Master board use LSB
            int crc = ModbusCRC.doCRC16(m_pSendBytes, 0, 6);
            m_pSendBytes[6] = (byte) (crc & 0x000000ff);
            m_pSendBytes[7] = (byte) ((crc & 0x0000ff00) >> 8);
        }
    }

    /**
     * @return the m_timeInterval
     */
    public long getTimeInterval() {
        return m_timeInterval;
    }

    /**
     * This function modify the time interval. Stop the current timer and start
     * it again with the new time interval.
     *
     * @param timeInterval the m_timeInterval to set
     */
    public void setTimeInterval(long timeInterval) {
        this.m_timeInterval = timeInterval;
        this.stop();
        this.start();
    }
}
